/***** BEGIN LICENSE BLOCK *****
 * Version: CPL 1.0/GPL 2.0/LGPL 2.1
 *
 * The contents of this file are subject to the Common Public
 * License Version 1.0 (the "License"); you may not use this file
 * except in compliance with the License. You may obtain a copy of
 * the License at http://www.eclipse.org/legal/cpl-v10.html
 *
 * Software distributed under the License is distributed on an "AS
 * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
 * implied. See the License for the specific language governing
 * rights and limitations under the License.
 *
 * Copyright (C) 2001 Alan Moore <alan_moore@gmx.net>
 * Copyright (C) 2001-2004 Jan Arne Petersen <jpetersen@uni-bonn.de>
 * Copyright (C) 2002 Benoit Cerrina <b.cerrina@wanadoo.fr>
 * Copyright (C) 2002-2004 Anders Bengtsson <ndrsbngtssn@yahoo.se>
 * Copyright (C) 2002-2004 Thomas E Enebo <enebo@acm.org>
 * Copyright (C) 2004 Stefan Matthias Aust <sma@3plus4.de>
 * Copyright (C) 2006 Miguel Covarrubias <mlcovarrubias@gmail.com>
 * Copyright (C) 2006 Antti Karanta <Antti.Karanta@napa.fi>
 * 
 * Alternatively, the contents of this file may be used under the terms of
 * either of the GNU General Public License Version 2 or later (the "GPL"),
 * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
 * in which case the provisions of the GPL or the LGPL are applicable instead
 * of those above. If you wish to allow use of your version of this file only
 * under the terms of either the GPL or the LGPL, and not to allow others to
 * use your version of this file under the terms of the CPL, indicate your
 * decision by deleting the provisions above and replace them with the notice
 * and other provisions required by the GPL or the LGPL. If you do not delete
 * the provisions above, a recipient may use your version of this file under
 * the terms of any one of the CPL, the GPL or the LGPL.
 ***** END LICENSE BLOCK *****/
package asruby.lang {

import asruby.Ruby;
import asruby.asupport.RuntimeHelpers;
import asruby.exceptions.RaiseException;
import asruby.runtime.CallbackFactory;
import asruby.runtime.IRubyObject;
import asruby.runtime.MethodIndex;
import asruby.runtime.ThreadContext;

/**
 * Base class for all numerical types in ruby.
 */
// TODO: Numeric.new works in Ruby and it does here too.  However trying to use
//   that instance in a numeric operation should generate an ArgumentError. Doing
//   this seems so pathological I do not see the need to fix this now.
public class RubyNumeric extends RubyObject {
    
    public static function createNumericClass(runtime:Ruby):RubyClass{
        var numeric: RubyClass =  runtime.defineClass("Numeric", runtime.getObject(), NUMERIC_ALLOCATOR);
        runtime.setNumeric(numeric);
        var callbackFactory: CallbackFactory =  runtime.callbackFactory(RubyNumeric);

        numeric.kindOf = 
            function isKindOf(obj:IRubyObject, type:RubyModule):Boolean{
                return obj instanceof RubyNumeric;
            };

        //numeric.includeModule(runtime.getComparable());
        numeric.defineAnnotatedMethods(RubyNumeric);
        numeric.dispatcher = callbackFactory.createDispatcher(numeric);

        return numeric;
    }

    protected static var NUMERIC_ALLOCATOR: Function = 
        function allocate(runtime:Ruby, klass:RubyClass):IRubyObject{
            return new RubyNumeric(runtime, klass);
        };

    //public static var DBL_EPSILON: double = 2.2204460492503131e-16;
    
    public  function RubyNumeric(runtime:Ruby, metaClass:RubyClass, useObjectSpace:Boolean=false){
        super(runtime, metaClass, useObjectSpace);
    }    

    // The implementations of these are all bonus (see TODO above)  I was going
    // to throw an error from these, but it appears to be the wrong place to
    // do it.
    public  function getDoubleValue():Number{
        return 0;
    }

    public override function getLongValue():Number{
        return 0;
    }
    
    public static function newNumeric(runtime:Ruby):RubyNumeric{
    	return new RubyNumeric(runtime, runtime.getNumeric());
    }

    /*  ================
     *  Utility Methods
     *  ================ 
     */

    /** rb_num2int, NUM2INT
     * 
     */
    public static function num2int(arg:IRubyObject):int{
        var num: Number =  num2long(arg);

        //checkInt(arg, num);
        return num;
    }
    
    // check_int
/*
    public static function checkInt(arg:IRubyObject, num:Number):void{
        var s:String;
        if (num < Integer.MIN_VALUE) {
            s = "small";
        } else if (num > Integer.MAX_VALUE) {
            s = "big";
        } else {
            return;
        }
        throw arg.getRuntime().newRangeError("integer " + num + " too " + s + " to convert to `int'");
    }

    //NUM2CHR
    public static function num2chr(arg:IRubyObject):int{
        if (arg instanceof RubyString) {
            var value: String =  RubyString( arg).toString();

            if (value != null && value.length() > 0) return  value.charAt(0);
        } 

        return num2int(arg);
    }
*/
    /** rb_num2long and FIX2LONG (numeric.c)
     * 
     */
    public static function num2long(arg:IRubyObject):Number{
/*         if (arg instanceof RubyFixnum) {
            return ((RubyFixnum) arg).getLongValue();
        }
        if (arg.isNil()) {
            throw arg.getRuntime().newTypeError("no implicit conversion from nil to integer");
   		}

        if (arg instanceof RubyFloat) {
            var aFloat: Number =  ((RubyFloat) arg).getDoubleValue();
            if (aFloat <= (Number) Long.MAX_VALUE && aFloat >= (Number) Long.MIN_VALUE) {
                return (long) aFloat;
            } else {
                // TODO: number formatting here, MRI uses "%-.10g", 1.4 API is a must?
                throw arg.getRuntime().newRangeError("float " + aFloat + " out of range of integer");
            }
        } else if (arg instanceof RubyBignum) {
            return RubyBignum.big2long((RubyBignum) arg);
        }
        return arg.convertToInteger().getLongValue(); */
        return arg.getLongValue();
    }

    /** rb_dbl2big + LONG2FIX at once (numeric.c)
     * 
     */
/*     public static function dbl2num(runtime:Ruby, val:Number):IRubyObject{
        if (Double.isInfinite(val)) {
            throw runtime.newFloatDomainError(val < 0 ? "-Infinity" : "Infinity");
        }
        if (Double.isNaN(val)) {
            throw runtime.newFloatDomainError("NaN");
        }

        if (val >= (Number) RubyFixnum.MAX || val < (Number) RubyFixnum.MIN) {
            return RubyBignum.newBignum(runtime, val);
        }
        return RubyFixnum.newFixnum(runtime, (long) val);
    } */

    /** rb_num2dbl and NUM2DBL
     * 
     */
/*     public static function num2dbl(arg:IRubyObject):Number{
        if (arg instanceof RubyFloat) {
            return ((RubyFloat) arg).getDoubleValue();
        } else if (arg instanceof RubyString) {
            throw arg.getRuntime().newTypeError("no implicit conversion to float from string");
        } else if (arg == arg.getRuntime().getNil()) {
            throw arg.getRuntime().newTypeError("no implicit conversion to float from nil");
        }
        return arg.convertToFloat().getDoubleValue();
    } */

    /** rb_dbl_cmp (numeric.c)
     * 
     */
    public static function dbl_cmp(runtime:Ruby, a:Number, b:Number):IRubyObject{
/*         if (Number.isNaN(a) || Number.isNaN(b)) {
            return runtime.getNil();
        } */
        if (a > b) {
            return RubyFixnum.one(runtime);
        }
        if (a < b) {
            return RubyFixnum.minus_one(runtime);
        }
        return RubyFixnum.zero(runtime);
    }

/*     public static function fix2long(arg:IRubyObject):Number{
        return ((RubyFixnum) arg).getLongValue();
    } 

    public static function fix2int(arg:IRubyObject):int{
        var num: Number =  arg instanceof RubyFixnum ? fix2long(arg) : num2long(arg);

        checkInt(arg, num);
        return  num;
        }

    public static function str2inum(runtime:Ruby, str:RubyString, base:int):RubyInteger{
        return str2inum(runtime,str,base,false);
    }

    public static function int2fix(runtime:Ruby, val:Number):RubyNumeric{
        return RubyFixnum.newFixnum(runtime,val);
    }

    // rb_num2fix
    public static function num2fix(val:IRubyObject):IRubyObject{
        if (val instanceof RubyFixnum) {
            return val;
        }
        if (val instanceof RubyBignum) {
            // any BigInteger is bigger than Fixnum and we don't have FIXABLE
            throw val.getRuntime().newRangeError("integer " + val + " out of range of fixnum");
        }
        return RubyFixnum.newFixnum(val.getRuntime(), num2long(val));
    }


     * Converts a string representation of an integer to the integer value. 
     * Parsing starts at the beginning of the string (after leading and 
     * trailing whitespace have been removed), and stops at the end or at the 
     * first character that can't be part of an integer.  Leading signs are
     * allowed. If base</code> is zero, strings that begin with '0[xX]',
     * '0[bB]', or '0' (optionally preceded by a sign) will be treated as hex, 
     * binary, or octal numbers, respectively.  If a non-zero base is given, 
     * only the prefix (if any) that is appropriate to that base will be 
     * parsed correctly.  For example, if the base is zero or 16, the string
     * "0xff" will be converted to 256, but if the base is 10, it will come out 
     * as zero, since 'x' is not a valid decimal digit.  If the string fails 
     * to parse as a number, zero is returned.
     * 
     * @param runtime  the ruby runtime
     * @param str   the string to be converted
     * @param base  the expected base of the number (for example, 2, 8, 10, 16),
     *              or 0 if the method should determine the base automatically 
     *              (defaults to 10). Values 0 and 2-36 are permitted. Any other
     *              value will result in an ArgumentError.
     * @param strict if true, enforce the strict criteria for String encoding of
     *               numeric values, as required by Integer('n'), and raise an
     *               exception when those criteria are not met. Otherwise, allow
     *               lax expression of values, as permitted by String#to_i, and
     *               return a value in almost all cases (excepting illegal radix).
     *               TODO: describe the rules/criteria
     * @return  a RubyFixnum or (if necessary) a RubyBignum representing 
     *          the result of the conversion, which will be zero if the 
     *          conversion failed.
     *
    public static function str2inum2(runtime:Ruby, str:RubyString, base:int, strict:Boolean):RubyInteger{
        if (base != 0 && (base < 2 || base > 36)) {
            throw runtime.newArgumentError("illegal radix " + base);
            }
        var bytes: ByteList =  str.getByteList();
        try {
            return runtime.newFixnum(Convert.byteListToLong(bytes,base,strict));

        } catch (e:InvalidIntegerException) {
            if (strict) {
                throw runtime.newArgumentError("invalid value for Integer: "
                        + str.callMethod(runtime.getCurrentContext(), "inspect").toString());
            }
            return RubyFixnum.zero(runtime);
        } catch (e:NumberTooLargeException) {
        try {
                var bi: BigInteger =  Convert.byteListToBigInteger(bytes,base,strict);
                return new RubyBignum(runtime,bi);
            } catch (e2:InvalidIntegerException) {
                if(strict) {
                    throw runtime.newArgumentError("invalid value for Integer: "
                            + str.callMethod(runtime.getCurrentContext(), "inspect").toString());
                }
                return RubyFixnum.zero(runtime);
            }
        }
    }

    public static function str2fnum(runtime:Ruby, arg:RubyString):RubyFloat{
        return str2fnum(runtime,arg,false);
    }
   
     * Converts a string representation of a floating-point number to the 
     * numeric value.  Parsing starts at the beginning of the string (after 
     * leading and trailing whitespace have been removed), and stops at the 
     * end or at the first character that can't be part of a number.  If 
     * the string fails to parse as a number, 0.0 is returned.
     * 
     * @param runtime  the ruby runtime
     * @param arg   the string to be converted
     * @param strict if true, enforce the strict criteria for String encoding of
     *               numeric values, as required by Float('n'), and raise an
     *               exception when those criteria are not met. Otherwise, allow
     *               lax expression of values, as permitted by String#to_f, and
     *               return a value in all cases.
     *               TODO: describe the rules/criteria
     * @return  a RubyFloat representing the result of the conversion, which
     *          will be 0.0 if the conversion failed.
     *
    public static function str2fnum2(runtime:Ruby, arg:RubyString, strict:Boolean):RubyFixnum {
        var ZERO: Number =  0.0;
        
        try {
            return new RubyFixnum(runtime,Convert.byteListToDouble(arg.getByteList(),strict));
        } catch (e:Error) {
            if (strict) {
                throw runtime.newArgumentError("invalid value for Float(): "
                        + arg.callMethod(runtime.getCurrentContext(), "inspect").toString());
            }
            return new RubyFloat(runtime,ZERO);
        }
    }
    
    // Numeric methods. (num_*)
    protected  function getCoerced(context:ThreadContext, other:IRubyObject, error:Boolean):Array{
        var result:IRubyObject;
        
        try {
            result = other.callMethod2(context, "coerce", this);
        } catch (e:RaiseException) {
            if (error) {
                throw getRuntime().newTypeError(
                        other.getMetaClass().getName() + " can't be coerced into " + getMetaClass().getName());
            }
             
            return null;
        }
        
        if (!(result instanceof RubyArray) || RubyArray(result).getLength() != 2) {
            throw getRuntime().newTypeError("coerce must return [x, y]");
        }
        
        return RubyArray(result).toJavaArray();
    }

    protected  function callCoerced(context:ThreadContext, method:String, other:IRubyObject, err:Boolean):IRubyObject{
        var args: Array =  getCoerced(context, other, err);
        if(args == null) {
            return getRuntime().getNil();
        }
        return args[0].callMethod(context, method, args[1]);
    }

    protected  function callCoerced2(context:ThreadContext, method:String, other:IRubyObject):IRubyObject{
        var args: Array =  getCoerced(context, other, false);
        if(args == null) {
            return getRuntime().getNil();
        }
        return args[0].callMethod(context, method, args[1]);
    }
    
    // beneath are rewritten coercions that reflect MRI logic, the aboves are used only by RubyBigDecimal

    //coerce_body    
    protected  function coerceBody(context:ThreadContext, other:IRubyObject):IRubyObject{
        return other.callMethod2(context, "coerce", this);
    }
*/
    /** do_coerce
     * 
     */
    protected  function doCoerce(context:ThreadContext, other:IRubyObject, err:Boolean):RubyArray{
        var result:IRubyObject;
        try {
            result = coerceBody(context, other);
        } catch (e:RaiseException) {
            if (err) {
                throw getRuntime().newTypeError(
                        other.getMetaClass().getName() + " can't be coerced into " + getMetaClass().getName());
            }
            return null;
        }
    
        if (!(result instanceof RubyArray) || RubyArray(result).getLength() != 2) {
            throw getRuntime().newTypeError("coerce must return [x, y]");
        }
        return RubyArray(result);
    }

    /** rb_num_coerce_bin
     *  coercion taking two arguments
     */
    protected  function coerceBin(context:ThreadContext, method:String, other:IRubyObject):IRubyObject{
        var ary: RubyArray =  doCoerce(context, other, true);
        return (ary.eltInternal(0)).callMethod2(context, method, ary.eltInternal(1));
    }
    
    /** rb_num_coerce_cmp
     *  coercion used for comparisons
     */
    protected  function coerceCmp(context:ThreadContext, method:String, other:IRubyObject):IRubyObject{
        var ary: RubyArray =  doCoerce(context, other, false);
        if (ary == null) {
            return getRuntime().getNil(); // MRI does it!
        } 
        return (ary.eltInternal(0)).callMethod2(context, method, ary.eltInternal(1));
    }
        
    /** rb_num_coerce_relop
     *  coercion used for relative operators
     */
    protected  function coerceRelOp(context:ThreadContext, method:String, other:IRubyObject):IRubyObject{
        var ary: RubyArray =  doCoerce(context, other, false);
        if (ary != null) {
            var result: IRubyObject =  (ary.eltInternal(0)).callMethod(context, method,ary.eltInternal(1));
            if (!result.isNil()) {
                return result;
            }
        }
    
        RubyComparable.cmperr(this, other); // MRI also does it that way       
        return null; // not reachd as in MRI
    } 
        
    public  function asNumeric():RubyNumeric{
        return this;
    }

    /*  ================
     *  Instance Methods
     *  ================ 
     */

    /** num_sadded
     *
     */
    public  function sadded(name:IRubyObject):IRubyObject{
        throw getRuntime().newTypeError("can't define singleton method " + name + " for " + getType().getName());
    } 
        
    /** num_init_copy
     *
     */
    public override function initialize_copy(arg:IRubyObject):IRubyObject{
        throw getRuntime().newTypeError("can't copy " + getType().getName());
    }
    
    /** num_coerce
     *
     */
    public  function coerce(other:IRubyObject):IRubyObject{
        if (getMetaClass() == other.getMetaClass()) {
            return getRuntime().newArray(other, this);
        } 

        return getRuntime().newArray(other,this);// RubyKernel.new_float(this, this));
    }

    /** num_uplus
     *
     */
    public  function op_uplus():IRubyObject{
        return this;
    }

    /** num_uminus
     *
     */
    public  function op_uminus(context:ThreadContext):IRubyObject{
        var zero: RubyFixnum =  RubyFixnum.zero(getRuntime());
        var ary: RubyArray =  zero.doCoerce(context, this, true);
        return ary.eltInternal(0).callMethod(context, MethodIndex.OP_MINUS, "-", ary.eltInternal(1));
    }
    
    /** num_cmp
     *
     */
    public  function op_cmp(other:IRubyObject):IRubyObject{
        if (this == other) { // won't hurt fixnums
            return RubyFixnum.zero(getRuntime());
        }
        return getRuntime().getNil();
    }

    /** num_eql
     *
     */
    public override function eql_p(context:ThreadContext, other:IRubyObject):IRubyObject{
        if (getMetaClass() != other.getMetaClass()) {
            return getRuntime().getFalse();
        }
        return op_equal(context, other);
    }
            
    /** num_quo
     *
     */
    public  function quo(context:ThreadContext, other:IRubyObject):IRubyObject{
        return callMethod(context, "/", other);
    }

    /** num_div
     * 
     */
    public  function div(context:ThreadContext, other:IRubyObject):IRubyObject{
        return callMethod(context, "/", other).convertToFloat().floor();
    }

    /** num_divmod
     * 
     */
    public  function divmod(context:ThreadContext, other:IRubyObject):IRubyObject{
        return RubyArray.newArray(getRuntime(), div(context, other), modulo(context, other));
    }

    /** num_modulo
     *
     */
    public  function modulo(context:ThreadContext, other:IRubyObject):IRubyObject{
        return callMethod(context, "%", other);
    }

    /** num_remainder
     *
     */
    public  function remainder(context:ThreadContext, dividend:IRubyObject):IRubyObject{
        var z: IRubyObject =  callMethod(context, "%", dividend);
        var x: IRubyObject =  this;
        var zero: RubyFixnum =  RubyFixnum.zero(getRuntime());

        if (z.op_equal(context, zero).isTrue()) {
            return z;
        } else if (x.callMethod(context, MethodIndex.OP_LT, "<", zero).isTrue()
                        && dividend.callMethod(context, MethodIndex.OP_GT, ">", zero).isTrue()
                   || x.callMethod(context, MethodIndex.OP_GT, ">", zero).isTrue()
                        && (dividend.callMethod(context, MethodIndex.OP_LT, "<", zero)).isTrue()) {
            return z.callMethod(context, MethodIndex.OP_MINUS, "-",dividend);
        } else {
            return z;
        }
    }

    /** num_abs
     *
     */
    public  function abs(context:ThreadContext):IRubyObject{
        if (callMethod(context, MethodIndex.OP_LT, "<", RubyFixnum.zero(getRuntime())).isTrue()) {
            return RubyNumeric( callMethod(context, "-@") );
        }
        return this;
    }
    
    /** num_to_int
     * 
     */
    public  function to_int(context:ThreadContext):IRubyObject{
        return RuntimeHelpers.invoke7(context, this, MethodIndex.TO_I, "to_i", RubyObject.NULL_ARRAY);
    }

    /** num_int_p
     *
     */
    public  function integer_p():IRubyObject{
        return getRuntime().getFalse();
    }
    
    /** num_zero_p
     *
     */
    public  function zero_p(context:ThreadContext):IRubyObject{
        // Will always return a boolean
        return op_equal(context, RubyFixnum.zero(getRuntime())).isTrue() ? getRuntime().getTrue() : getRuntime().getFalse();
    }
    
    /** num_nonzero_p
     *
     */
    public  function nonzero_p(context:ThreadContext):IRubyObject{
        if (callMethod(context, "zero?").isTrue()) {
            return getRuntime().getNil();
        }
        return this;
    }

    /** num_floor
     *
     */
    public  function floor():IRubyObject{
        return convertToFloat().floor();
    }
        
    /** num_ceil
     *
     */
    public  function ceil():IRubyObject{
        return convertToFloat().ceil();
    }

    /** num_round
     *
     */
    public  function round():IRubyObject{
        return convertToFloat().round();
    }
/*
    // num_truncate
    public  function truncate():IRubyObject{
        return convertToFloat().truncate();
    }
    
    public  function step(context:ThreadContext, args:Array, block:Block):IRubyObject{
        var toval:IRubyObject;
        var step:IRubyObject;
        
        if(args.length == 1){ 
            toval = args[0];
            step = RubyFixnum.one(getRuntime());
        } else if (args.length == 2) {
            toval = args[0];
            step = args[1];
        }else{
            throw getRuntime().newTypeError("wrong number of arguments");
        }
        
        if (this instanceof RubyFixnum && toval instanceof RubyFixnum && step instanceof RubyFixnum) {
            var value: Number =  getLongValue();
            var end: Number =  RubyFixnum( toval).getLongValue();
            var diff: Number =  RubyFixnum(step).getLongValue();

            if (diff == 0) {
                throw getRuntime().newArgumentError("step cannot be 0");
            }
            if (diff > 0) {
                for ( var i:Number = value; i <= end; i += diff) {
                    block.yield(context, RubyFixnum.newFixnum(getRuntime(), i));
                }
            } else {
                for ( var i:Number = value; i >= end; i += diff) {
                    block.yield(context, RubyFixnum.newFixnum(getRuntime(), i));
                }
            }
        } else if (this instanceof RubyFloat || toval instanceof RubyFloat || step instanceof RubyFloat) {
            var beg: Number =  num2dbl(this);
            var _end: Number =  num2dbl(toval);
            var unit: Number =  num2dbl(step);

            if (unit == 0) {
                throw getRuntime().newArgumentError("step cannot be 0");
            }           
            
            var n: Number =  (_end - beg)/unit;
            var err: Number =  (Math.abs(beg) + Math.abs(_end) + Math.abs(_end - beg)) / Math.abs(unit) * DBL_EPSILON;
            
            if (err>0.5) {
                err = 0.5;            
            }
            n = Math.floor(n + err) + 1;
            
            for ( var i:Number = 0; i < n; i++){
                block.yield(context, RubyFloat.newFloat(getRuntime(), i * unit + beg));
            }

        } else {
            var i: RubyNumeric =  this;
            
            var cmp:int;
            var cmpString:String;
            if (RubyBoolean( step.callMethod(context, MethodIndex.OP_GT, ">", RubyFixnum.zero(getRuntime()))).isTrue()) {
                cmp = MethodIndex.OP_GT;
            } else {
                cmp = MethodIndex.OP_LT;
            }
            cmpString = MethodIndex.NAMES.get(cmp);

            while (true) {
                if (i.callMethod(context, cmp, cmpString, toval).isTrue()) {
                    break;
                }
                block.yield(context, i);
                i = RubyNumeric( i.callMethod(context, MethodIndex.OP_PLUS, "+", step));
            }
        }
        return this;
    }
*/
    /** num_equal, doesn't override RubyObject.op_equal
     *
     */
    protected  function op_num_equal(context:ThreadContext, other:IRubyObject):IRubyObject{
        // it won't hurt fixnums
        if (this == other)  return getRuntime().getTrue();

        return other.callMethod6(context, MethodIndex.EQUALEQUAL, "==", this);
    }

/*     public static class InvalidIntegerException extends NumberFormatException {
        private static var serialVersionUID: Number =  55019452543252148L;
        
        public  function InvalidIntegerException(){
            super();
        }
        public  function InvalidIntegerException(message:String){
            super(message);
        }
        public  function fillInStackTrace():Throwable{
            return this;
        }
    }
    
    public static class NumberTooLargeException extends NumberFormatException {
        private static var serialVersionUID: Number =  -1835120694982699449L;
        public  function NumberTooLargeException(){
            super();
        }
        public  function NumberTooLargeException(message:String){
            super(message);
        }
        public  function fillInStackTrace():Throwable{
            return this;
        }
    } */
  	public static function fix2Number(iRubyObj:IRubyObject):int{
  		return 0;
  	}
}
}